package com.fwj.core.common.annotation;

import com.fwj.core.common.common.CommonUtils;
import com.fwj.core.common.common.LogUtils;
import com.fwj.core.common.execption.CommonException;
import com.fwj.core.common.model.DataBuriedPointLogBean;
import com.fwj.core.common.model.ResponseEnum;
import com.fwj.user.entity.user.UserBaseInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.*;
/**
 * @Author: fwj
 * @Data: 2022/4/11 0:34
 * @Version 1.0
 * @Description: 全局获取当前登录用户，使用条件：在方法参数中添加 @LoginUser UserBaseInfo userBaseInfo
 */

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
public @interface LoginUser {


    String[] Roles() default "";

    String[] Auth() default  "";

    @Component
    class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

        //添加日志工厂
        private static final Logger LOGGER = LoggerFactory.getLogger(LoginUser.class);

        //添加日志工厂
        private static final Logger DBPLOGGER = LoggerFactory.getLogger(DataBuriedPointLog.class);

        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return (parameter.getParameterType().isAssignableFrom(UserBaseInfo.class)) &&
                    parameter.hasParameterAnnotation(LoginUser.class);
        }


        // 具体映射规则
        @Override
        public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer
                modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
            // 全局获取 request
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            //拿到request中的数据
            DataBuriedPointLogBean dataBuriedPointLogBean = LogUtils.buildDataBuriedPointLog(request);
            //获取登录会话信息
            String authSession = getAuthSession(request,dataBuriedPointLogBean);
            //查找登录信息
            UserBaseInfo userBaseInfo = getLoginUser(authSession, dataBuriedPointLogBean);
            return userBaseInfo;
        }

        /**
         * @Description 获取登录信息
         * @Param: request
         * @Author fwj
         * @return java.lang.String
         * @Createtime 2022/4/11
         */
        private String getAuthSession(HttpServletRequest request, DataBuriedPointLogBean dataBuriedPointLogBean) {
            String authSession = CommonUtils.getAuthSession(request);
            //如果未登录则抛出异常,终止流程
            if (CommonUtils.isEmpty(authSession)){
                LOGGER.info("未登录");
                DBPLOGGER.info("未登录:  " + dataBuriedPointLogBean.toString());
                throw new CommonException(ResponseEnum.USER_NO_LOGIN);
            }
            return authSession;
        }

        /**
         * @Description 检查是否登录并获取登录对象
         * @Param: authSession
         * @Author fwj
         * @return com.fwj.user.entity.user.UserBaseInfo
         * @Createtime 2022/4/11
         */
        private UserBaseInfo getLoginUser(String authSession, DataBuriedPointLogBean dataBuriedPointLogBean) {
            //获取Redis中的数据
            UserBaseInfo userBaseInfo = CommonUtils.getUserBaseInfo(authSession);
            if (CommonUtils.isEmpty(userBaseInfo)){
                LOGGER.error("未登录");
                DBPLOGGER.info("未登录:  " + dataBuriedPointLogBean.toString());
                throw new CommonException(ResponseEnum.USER_NO_LOGIN);
            }
            return userBaseInfo;
        }
    }
}
